//
// Copyright (C) 2024 Kumo group inc.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <krpc/rpc/config.h>

TURBO_FLAG(bool, usercode_in_pthread, false,
           "Call user's callback in pthreads, use fibers otherwise");

TURBO_FLAG(int32_t, event_dispatcher_num, 1, "Number of event dispatcher");

TURBO_FLAG(bool, usercode_in_coroutine, false,
           "User's callback are run in coroutine, no fiber or pthread blocking call");


// NOTE: This flag was true by default before r31206. Connected to somewhere
// is not an important event now, we can check the connection in /connections
// if we're in doubt.
TURBO_FLAG(bool, log_connected, false, "Print log when a connection is established").on_validate(
        turbo::AllPassValidator<bool>::validate);

TURBO_FLAG(bool, log_idle_connection_close, false,
           "Print log when an idle connection is closed").on_validate(turbo::AllPassValidator<bool>::validate);

TURBO_FLAG(int32_t, socket_recv_buffer_size, -1,
           "Set the recv buffer size of socket if this value is positive");

// Default value of SNDBUF is 2500000 on most machines.
TURBO_FLAG(int32_t, socket_send_buffer_size, -1,
           "Set send buffer size of sockets if this value is positive");

TURBO_FLAG(int32_t, ssl_bio_buffer_size, 16 * 1024, "Set buffer size for SSL read/write");

TURBO_FLAG(int64_t, socket_max_unwritten_bytes, 64 * 1024 * 1024,
           "Max unwritten bytes in each socket, if the limit is reached,"
           " Socket.Write fails with EOVERCROWDED");

TURBO_FLAG(int64_t, socket_max_streams_unconsumed_bytes, 0,
           "Max stream receivers' unconsumed bytes in one socket,"
           " it used in stream for receiver buffer control.");

TURBO_FLAG(int32_t, max_connection_pool_size, 100,
           "Max number of pooled connections to a single endpoint").on_validate(
        turbo::AllPassValidator<int32_t>::validate);

TURBO_FLAG(int32_t, connect_timeout_as_unreachable, 3,
           "If the socket failed to connect due to ETIMEDOUT for so many "
           "times *continuously*, the error is changed to ENETUNREACH which "
           "fails the main socket as well when this socket is pooled.").on_validate(
        turbo::ClosedOpenInRangeValidator<int32_t, 2, 1000>::validate);


TURBO_FLAG(int32_t, health_check_interval, 3,
           "seconds between consecutive health-checkings").on_validate(turbo::GtValidator<int32_t, 0>::validate);

TURBO_FLAG(int32_t, idle_timeout_second, 30,
           "Pooled connections without data transmission for so many "
           "seconds will be closed. No effect for non-positive values").on_validate(
        turbo::AllPassValidator<int32_t>::validate);

TURBO_FLAG(int32_t, defer_close_second, 0,
           "Defer close of connections for so many seconds even if the"
           " connection is not used by anyone. Close immediately for "
           "non-positive values.").on_validate(turbo::AllPassValidator<int32_t>::validate);

TURBO_FLAG(bool, show_socketmap_in_vars, false,
           "[DEBUG] Describe SocketMaps in /vars").on_validate(turbo::AllPassValidator<bool>::validate);

TURBO_FLAG(bool, reserve_one_idle_socket, false,
           "Reserve one idle socket for pooled connections when idle_timeout_second > 0");

TURBO_FLAG(std::string, health_check_path, "", "Http path of health check call."
                                               "By default health check succeeds if the server is connectable."
                                               "If this flag is set, health check is not completed until a http "
                                               "call to the path succeeds within -health_check_timeout_ms(to make "
                                               "sure the server functions well).");
TURBO_FLAG(int32_t, health_check_timeout_ms, 500, "The timeout for both establishing "
                                                  "the connection and the http call to -health_check_path over the connection");


TURBO_FLAG(bool, allow_chunked_length, false,
           "Allow both Transfer-Encoding and Content-Length headers are present.");
TURBO_FLAG(bool, allow_http_1_1_request_without_host, true,
           "Allow HTTP/1.1 request without host which violates the HTTP/1.1 specification.");
TURBO_FLAG(bool, http_verbose, false,
           "[DEBUG] Print EVERY http request/response");
TURBO_FLAG(int32_t, http_verbose_max_body_length, 512,
           "[DEBUG] Max body length printed when -http_verbose is on");

TURBO_FLAG(int32_t, channel_check_interval, 1,
           "seconds between consecutive health-checking of unaccessible"
           " sub channels inside SelectiveChannel");
#if KRPC_WITH_RDMA
TURBO_FLAG(int32_t, rdma_max_sge, 0, "Max SGE num in a WR");
TURBO_FLAG(std::string, rdma_device, "", "The name of the HCA device used "
"(Empty means using the first active device)");
TURBO_FLAG(int32_t, rdma_port, 1, "The port number to use. For RoCE, it is always 1.");
TURBO_FLAG(int32_t, rdma_gid_index, -1, "The GID index to use. -1 means using the last one.");
//////////////////////
TURBO_FLAG(int32_t, rdma_sq_size, 128, "SQ size for RDMA");
TURBO_FLAG(int32_t, rdma_rq_size, 128, "RQ size for RDMA");
TURBO_FLAG(bool, rdma_recv_zerocopy, true, "Enable zerocopy for receive side");
TURBO_FLAG(int32_t, rdma_zerocopy_min_size, 512, "The minimal size for receive zerocopy");
TURBO_FLAG(std::string, rdma_recv_block_type, "default", "Default size type for recv WR: "
              "default(8KB - 32B)/large(64KB - 32B)/huge(2MB - 32B)");
TURBO_FLAG(int32_t, rdma_cqe_poll_once, 32, "The maximum of cqe number polled once.");
TURBO_FLAG(int32_t, rdma_prepared_qp_size, 128, "SQ and RQ size for prepared QP.");
TURBO_FLAG(int32_t, rdma_prepared_qp_cnt, 1024, "Initial count of prepared QP.");
TURBO_FLAG(bool, rdma_trace_verbose, false, "Print log message verbosely").on_validate(turbo::AllPassValidator<bool>::validate);
#endif  // KRPC_WITH_RDMA

TURBO_FLAG(bool, rpc_dump, false,
           "Dump requests into files so that they can replayed "
           "laterly. Flags prefixed with \"rpc_dump_\" are not effective "
           "until this flag is true").on_validate(turbo::AllPassValidator<bool>::validate);
TURBO_FLAG(std::string, rpc_dump_dir, "./rpc_data/rpc_dump/<app>",
           "The directory of dumped files, will be cleaned "
           "if it exists when this process starts");
TURBO_FLAG(int32_t, rpc_dump_max_files, 32,
           "Max number of dumped files in a directory. "
           "If new file is needed, oldest file is removed.").on_validate(turbo::GtValidator<int32_t, 0>::validate);
TURBO_FLAG(int32_t, rpc_dump_max_requests_in_one_file, 1000,
           "Max number of requests in one dumped file").on_validate(turbo::GtValidator<int32_t, 0>::validate);


TURBO_FLAG(uint64_t, max_body_size, 64 * 1024 * 1024,
           "Maximum size of a single message body in all protocols");

TURBO_FLAG(bool, log_error_text, false,
           "Print Controller.ErrorText() when server is about to"
           " respond a failed RPC").on_validate(turbo::AllPassValidator<bool>::validate);

TURBO_FLAG(int32_t, timeout_cl_sample_window_size_ms, 1000,
           "Duration of the sampling window.");
TURBO_FLAG(int32_t, timeout_cl_min_sample_count, 100,
           "During the duration of the sampling window, if the number of "
           "requests collected is less than this value, the sampling window "
           "will be discarded.");
TURBO_FLAG(int32_t, timeout_cl_max_sample_count, 200,
           "During the duration of the sampling window, once the number of "
           "requests collected is greater than this value, even if the "
           "duration of the window has not ended, the max_concurrency will "
           "be updated and a new sampling window will be started.");
TURBO_FLAG(double, timeout_cl_sampling_interval_ms, 0.1,
           "Interval for sampling request in auto concurrency limiter");
TURBO_FLAG(int32_t, timeout_cl_initial_avg_latency_us, 500,
           "Initial max concurrency for gradient concurrency limiter");
TURBO_FLAG(bool,
           timeout_cl_enable_error_punish, true,
           "Whether to consider failed requests when calculating maximum concurrency");
TURBO_FLAG(double,
           timeout_cl_fail_punish_ratio, 1.0,
           "Use the failed requests to punish normal requests. The larger "
           "the configuration item, the more aggressive the penalty strategy.");
TURBO_FLAG(int32_t, timeout_cl_default_timeout_ms, 500,
           "Default timeout for rpc request");
TURBO_FLAG(int32_t, timeout_cl_max_concurrency, 100,
           "When average latency statistics not refresh, this flag can keep "
           "requests not exceed this max concurrency");


// NOTE: This flag was true by default before r31206. But since we have
// /connections to view all the active connections, logging closing does not
// help much to locate problems, and crashings are unlikely to be associated
// with an EOF.
TURBO_FLAG(bool, log_connection_close, false,
           "Print log when remote side closes the connection").on_validate(turbo::AllPassValidator<bool>::validate);


TURBO_FLAG(bool, socket_keepalive, false,
           "Enable keepalive of sockets if this value is true");

TURBO_FLAG(int32_t, socket_keepalive_idle_s, -1,
           "Set idle time of sockets before keepalive if this value is positive");

TURBO_FLAG(int32_t, socket_keepalive_interval_s, -1,
           "Set interval of sockets between keepalives if this value is positive");

TURBO_FLAG(int32_t, socket_keepalive_count, -1,
           "Set number of keepalives of sockets before close if this value is positive");

TURBO_FLAG(bool, redis_verbose, false,
           "[DEBUG] Print EVERY redis request/response");

TURBO_FLAG(bool, redis_verbose_crlf2space, false, "[DEBUG] Show \\r\\n as a space");

TURBO_FLAG(bool, show_lb_in_vars, false, "Describe LoadBalancers in vars").on_validate(
        turbo::AllPassValidator<bool>::validate);
TURBO_FLAG(int32_t, default_weight_of_wlb, 0, "Default weight value of Weighted LoadBalancer(wlb). "
                                              "wlb policy degradation is enabled when default_weight_of_wlb > 0 to avoid some "
                                              "problems when user is using wlb but forgot to set the weights of some of their "
                                              "downstream instances. Then these instances will be set default_weight_of_wlb as "
                                              "their weights. wlb policy degradation is not enabled by default.");

TURBO_FLAG(int32_t, free_memory_to_system_interval, 0,
           "Try to return free memory to system every so many seconds, "
           "values <= 0 disables this feature").on_validate(turbo::AllPassValidator<int32_t>::validate);

TURBO_FLAG(bool, show_hostname_instead_of_ip, false,
           "/connections shows hostname instead of ip").on_validate(turbo::AllPassValidator<bool>::validate);

TURBO_FLAG(int32_t, max_shown_connections, 1024,
           "Print stats of at most so many connections (soft limit)");

// Following services may have security issues and are disabled by default.
TURBO_FLAG(bool, enable_dir_service, true, "Enable /builtin/dir");
TURBO_FLAG(bool, enable_threads_service, true, "Enable /builtin/threads");

TURBO_FLAG(int32_t, usercode_backup_threads, 5, "# of backup threads to run user code"
                                                " when too many pthread worker of kthreads are used");
TURBO_FLAG(int32_t, max_pending_in_each_backup_thread, 10,
           "Max number of un-run user code in each backup thread, requests"
           " still coming in will be failed");

TURBO_FLAG(bool, enable_rpcz, false, "Turn on rpcz").on_validate(turbo::AllPassValidator<bool>::validate);

TURBO_FLAG(bool, rpcz_hex_log_id, false, "Show log_id in hexadecimal").on_validate(
        turbo::AllPassValidator<bool>::validate);


TURBO_FLAG(int32_t, circuit_breaker_short_window_size, 1500,
           "Short window sample size.");
TURBO_FLAG(int32_t, circuit_breaker_long_window_size, 3000,
           "Long window sample size.");
TURBO_FLAG(int32_t, circuit_breaker_short_window_error_percent, 10,
           "The maximum error rate allowed by the short window, ranging from 0-99.");
TURBO_FLAG(int32_t, circuit_breaker_long_window_error_percent, 5,
           "The maximum error rate allowed by the long window, ranging from 0-99.");
TURBO_FLAG(int32_t, circuit_breaker_min_error_cost_us, 500,
           "The minimum error_cost, when the ema of error cost is less than this "
           "value, it will be set to zero.");
TURBO_FLAG(int32_t, circuit_breaker_max_failed_latency_mutiple, 2,
           "The maximum multiple of the latency of the failed request relative to "
           "the average latency of the success requests.");
TURBO_FLAG(int32_t, circuit_breaker_min_isolation_duration_ms, 100,
           "Minimum isolation duration in milliseconds");
TURBO_FLAG(int32_t, circuit_breaker_max_isolation_duration_ms, 30000,
           "Maximum isolation duration in milliseconds");
TURBO_FLAG(double, circuit_breaker_epsilon_value, 0.02,
           "ema_alpha = 1 - std::pow(epsilon, 1.0 / window_size)");
TURBO_FLAG(int32_t, circuit_breaker_half_open_window_size, 0,
           "The limited number of requests allowed to pass through by the half-open "
           "window. Only if all of them are successful, the circuit breaker will "
           "go to the closed state. Otherwise, it goes back to the open state. "
           "Values == 0 disables this feature").on_validate(turbo::GtValidator<int32_t, 0>::validate);


TURBO_FLAG(int32_t, auto_cl_sample_window_size_ms, 1000, "Duration of the sampling window.");
TURBO_FLAG(int32_t, auto_cl_min_sample_count, 100,
           "During the duration of the sampling window, if the number of "
           "requests collected is less than this value, the sampling window "
           "will be discarded.");
TURBO_FLAG(int32_t, auto_cl_max_sample_count, 200,
           "During the duration of the sampling window, once the number of "
           "requests collected is greater than this value, even if the "
           "duration of the window has not ended, the max_concurrency will "
           "be updated and a new sampling window will be started.");
TURBO_FLAG(double, auto_cl_sampling_interval_ms, 0.1,
           "Interval for sampling request in auto concurrency limiter");
TURBO_FLAG(int32_t, auto_cl_initial_max_concurrency, 40,
           "Initial max concurrency for gradient concurrency limiter");
TURBO_FLAG(int32_t, auto_cl_noload_latency_remeasure_interval_ms, 50000,
           "Interval for remeasurement of noload_latency. In the period of "
           "remeasurement of noload_latency will halve max_concurrency.");
TURBO_FLAG(double, auto_cl_alpha_factor_for_ema, 0.1,
           "The smoothing coefficient used in the calculation of ema, "
           "the value range is 0-1. The smaller the value, the smaller "
           "the effect of a single sample_window on max_concurrency.");
TURBO_FLAG(bool, auto_cl_enable_error_punish, true,
           "Whether to consider failed requests when calculating maximum concurrency");
TURBO_FLAG(double, auto_cl_fail_punish_ratio, 1.0,
           "Use the failed requests to punish normal requests. The larger "
           "the configuration item, the more aggressive the penalty strategy.");
TURBO_FLAG(double, auto_cl_max_explore_ratio, 0.3,
           "The larger the value, the higher the tolerance of the server to "
           "the fluctuation of latency at low load, and the the greater the "
           "maximum growth rate of qps. Correspondingly, the server will have "
           "a higher latency for a short period of time after the overload.");
TURBO_FLAG(double, auto_cl_min_explore_ratio, 0.06,
           "Auto concurrency limiter will perform fault tolerance based on "
           "this parameter when judging the load situation of the server. "
           "It should be a positive value close to 0, the larger it is, "
           "the higher the latency of the server at full load.");
TURBO_FLAG(double, auto_cl_change_rate_of_explore_ratio, 0.02,
           "The speed of change of auto_cl_max_explore_ratio when the "
           "load situation of the server changes, The value range is "
           "(0 - `max_explore_ratio')");
TURBO_FLAG(double, auto_cl_reduce_ratio_while_remeasure, 0.9,
           "This value affects the reduction ratio to mc during retesting "
           "noload_latency. The value range is (0-1)");
TURBO_FLAG(int32_t, auto_cl_latency_fluctuation_correction_factor, 1,
           "Affect the judgement of the server's load situation. The larger "
           "the value, the higher the tolerance for the fluctuation of the "
           "latency. If the value is too large, the latency will be higher "
           "when the server is overloaded.");

TURBO_FLAG(int64_t, detect_available_server_interval_ms, 10, "The interval "
                                                             "to detect available server count in DefaultClusterRecoverPolicy");

TURBO_FLAG(int32_t, ns_access_interval, 5,
           "Wait so many seconds before next access to naming service").on_validate(
        turbo::GtValidator<int32_t, 0>::validate);

TURBO_FLAG(int32_t, chash_num_replicas, 100,
           "default number of replicas per server in chash");

TURBO_FLAG(int32_t, max_tc_stats_buf_len, 32 * 1024, "max length of TCMalloc stats").on_validate(
        turbo::GtValidator<int32_t, 0>::validate);

TURBO_FLAG(int32_t, max_profiling_seconds, 300, "upper limit of running time of profilers").on_validate(
        turbo::GtValidator<int32_t, 0>::validate);
TURBO_FLAG(int32_t, max_profiles_kept, 32,
           "max profiles kept for cpu/heap/growth/contention respectively").on_validate(
        turbo::AllPassValidator<int32_t>::validate);

TURBO_FLAG(int32_t, max_flame_graph_width, 1200, "max width of flame graph image").on_validate(
        turbo::GtValidator<int32_t, 0>::validate);
